package VideoProcessing;

import java.awt.image.WritableRaster;
import java.util.Arrays;

import javax.media.format.VideoFormat;

public class PixelizationDialate8Bit extends RgbVideoEffect {

	private int pixelSize = 30;

	public PixelizationDialate8Bit() {
	}

	/**
	 * @return the pixelSize
	 */
	public int getPixelSize() {
		return pixelSize;
	}

	/**
	 * @param pixelSize
	 *            the pixelSize to set
	 */
	public void setPixelSize(int pixelSize) {
		this.pixelSize = pixelSize;
	}

	@Override
	public String getName() {
		return "Object Dialate (Manhattan Dist)";
	}

	@Override
	protected boolean processRGB(byte[] bin, byte[] bout, VideoFormat format) {
		Arrays.fill(bout, 0, bout.length, (byte) 0);
		int[] oracle = createOracle(bin, format);
		int height = format.getSize().height;
		int width = format.getSize().width;
		int offset = width;

		for (int y = 0; y < height; y++) {
			for (int x = 0; x < width; x++) {
				bout[offset * y + x] = ((oracle[offset * y + x] <= pixelSize) ? (byte) 255
						: 0);
			}
		}
		return true;
	}

	/*
	 * @Override protected boolean processRGB(byte[] bin, byte[] bout,
	 * VideoFormat format) { int rowSize = pixelSize * format.getSize().width;
	 * int offset; int rowOffset = 0; int x, y; int sx, sy; int pixOff;
	 * Arrays.fill(bout, 0, bout.length, (byte) 0); for (y = 0; y <
	 * format.getSize().height; y += pixelSize) { offset = rowOffset; for (x =
	 * 0; x < format.getSize().width; x += pixelSize) {
	 * 
	 * // If any input pixel within the square is on (255), fill the
	 * corresponding square in the output. pixOff = offset; inputSearch: for (sy
	 * = 0; sy < pixelSize; sy++) { for (sx = 0; sx < pixelSize; sx++) {
	 * 
	 * // If we found a non-zero input pixel if (bin[pixOff + sx] != 0) {
	 * 
	 * // Fill the output square pixOff = offset; for (sy = 0; sy < pixelSize;
	 * sy++) { for (sx = 0; sx < pixelSize; sx++) { bout[pixOff + sx] = (byte)
	 * 255; } pixOff += format.getSize().width; }
	 * 
	 * break inputSearch; // Don't bother checking any more pixels in the input
	 * square! } } pixOff += format.getSize().width; }
	 * 
	 * offset += pixelSize; } rowOffset += rowSize; }
	 * 
	 * return true; }
	 */
	private int[] createOracle(byte[] bin, VideoFormat format) {
		int height = format.getSize().height;
		int width = format.getSize().width;
		int oracle[] = new int[height * width];
		int offset = width;

		for (int y = 0; y < height; y++) {
			for (int x = 0; x < width; x++) {
				if (bin[offset * y + x] != 0) {
					oracle[offset * y + x] = 1;
				} else {
					oracle[offset * y + x] = 0;
				}
			}
		}
		oracle = manhattan(oracle, height, width);
		return oracle;
	}

	private int[] manhattan(int[] oracle, int height, int width) {
		int offset = width;
		for (int y = 0; y < height; y++) {
			for (int x = 0; x < width; x++) {
				if (oracle[offset * y + x] == 1) {
					// first pass and pixel was on, it gets a zero
					oracle[offset * y + x] = 0;
				} else {
					// pixel was off
					// It is at most the sum of the lengths of the array away
					// from a pixel that is on
					oracle[offset * y + x] = height + width;
					// or one more than the pixel to the north
					if (y > 0)
						oracle[offset * y + x] = Math.min(
								oracle[offset * y + x], oracle[offset * (y - 1)
										+ x] + 1);
					// or one more than the pixel to the west
					if (x > 0)
						oracle[offset * y + x] = Math.min(
								oracle[offset * y + x], oracle[offset * y
										+ (x - 1)] + 1);
				}
			}
		}
		// traverse from bottom right to top left
		for (int y = (height - 1); y >= 0; y--) {
			for (int x = (width - 1); x >= 0; x--) {
				// either what we had on the first pass
				// or one more than the pixel to the south
				if (y + 1 < height)
					oracle[offset * y + x] = Math.min(oracle[offset * y + x],
							oracle[offset * (y + 1) + x] + 1);
				// or one more than the pixel to the east
				if (x + 1 < width)
					oracle[offset * y + x] = Math.min(oracle[offset * y + x],
							oracle[offset * y + (x + 1)] + 1);
			}
		}
		return oracle;
	}

	protected void updateImage(byte[] bout, VideoFormat vformat) {
		synchronized (displayImage) {
			// // Copy pixels to image
			WritableRaster rast = displayImage.getRaster();
			int[] pixel = new int[] { 0, 0, 0, 255 };
			int p = 0;
			for (int y = vformat.getSize().height - 1; y >= 0; y--) {
				for (int x = 0; x < vformat.getSize().width; x++) {
					pixel[0] = pixel[1] = pixel[2] = bout[p++];
					rast.setPixel(x, y, pixel);
				}
			}
		}
	}
}
